package com.qf.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.cache.CategoryCache;
import com.qf.cache.SceneCache;
import com.qf.entity.SysCategory;
import com.qf.entity.SysDevice;
import com.qf.entity.SysScene;
import com.qf.entity.SysUserInfo;
import com.qf.events.CommandEvent;
import com.qf.exceptions.AddDataException;
import com.qf.exceptions.QueryDataException;
import com.qf.exceptions.ResultCode;
import com.qf.mapper.SysDeviceDao;
import com.qf.mapper.SysDeviceMapper;
import com.qf.mapper.SysSceneMapper;
import com.qf.pojo.BaseUser;
import com.qf.pojo.CheckType;
import com.qf.service.DeviceService;
import com.qf.utils.SecurityUtils;
import com.qf.websocket.MyCommandHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * @Author ztf
 * @Date 21:45 2022/1/5
 **/
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class DeviceServiceImpl implements DeviceService {

    private SysDeviceDao sysDeviceDao;
    private SysDeviceMapper sysSceneMapper;
    private CategoryCache categoryCache;
    private SceneCache sceneCache;
    private ObjectMapper objectMapper;

    @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Autowired
    public void setSceneCache(SceneCache sceneCache) {
        this.sceneCache = sceneCache;
    }

    @Autowired
    public void setCategoryCache(CategoryCache categoryCache) {
        this.categoryCache = categoryCache;
    }

    @Autowired
    public void setSysDeviceDao(SysDeviceDao sysDeviceDao) {
        this.sysDeviceDao = sysDeviceDao;
    }
    @Autowired
    public void setSysSceneMapper(SysDeviceMapper sysSceneMapper) {
        this.sysSceneMapper = sysSceneMapper;
    }

    @Override
    public void addDevice(SysDevice device) throws ExecutionException {
        //参数校验
        Assert.isTrue(!device.isEmpty(CheckType.ADD), () -> {
            throw new AddDataException("添加设备失败，必须参数不完整", ResultCode.DATA_NULL);
        });
        //查询设备是否被绑定
        SysDevice currentDevice = sysDeviceDao.selectByPrimaryKey(device.getDeviceId());

        Assert.isTrue(currentDevice == null || Objects.equals(currentDevice.getDeviceId(), device.getDeviceId()), () -> {
            throw new AddDataException("设备已经被绑定到其他账号", ResultCode.DEVICE_ALREADY_BIND);
        });
//        SysUserInfo user = SecurityUtils.getUser();
//        device.setBindUserId(user.getuId());

        //测试用
        device.setBindUserId(24);
        //先根据分类id是否存在，
        SysCategory category = categoryCache.getValue(device.getCategyId());
        Assert.notNull(category, () -> {
            throw new AddDataException("分类不存在", ResultCode.DATA_NOT_EXIST);
        });

        device.setSceneId(device.getSceneId() == null ? -1 : device.getSceneId());
        //获取到用户的场景
        List<SysScene> sceneList = sceneCache.getSceneLoadingCache().get(24);
        if (device.getSceneId() != -1) {
            Assert.isTrue(sceneList.stream()
                    .map(SysScene::getSceneId)
                    .collect(Collectors.toList())
                    .contains(device.getSceneId()), () ->
            {
                throw new AddDataException("场景不存在", ResultCode.DATA_NOT_EXIST);
            });
        }

        device.setBindTime(new Date());

        sysSceneMapper.insertDevice(device);

    }

    @Override
    public SysDevice findById(String id) {
        Assert.notNull(id, () -> {
            throw new QueryDataException("没有传递主键", ResultCode.ID_NULL);
        });
        SysDevice device = sysDeviceDao.selectByPrimaryKey(id);
        return device;
    }


    @Override
    public void sendControl(String id, String command) throws JsonProcessingException {
        //检查设备绑定的用户
        SysDevice device = findById(id);
        Assert.notNull(device, () -> {
            throw new QueryDataException("没有查找到设备", ResultCode.DEVICE_NOT_EXIST);
        });
        BaseUser user = SecurityUtils.getUser();
        //查看设备绑定的是不是当前用户
        Assert.isTrue(device.getBindUserId().equals(user.getUserId()), () -> {
            throw new QueryDataException("当前设备以绑定其他用户", ResultCode.DEVICE_CONTROL_NOTALLOWED);
        });
        Assert.isTrue(device.getIsOnline() == 1, () -> {
            throw new QueryDataException("设备不在线", ResultCode.DEVICE_OFFLINE);
        });

        Integer categyId = device.getCategyId();
        SysCategory category = categoryCache.getValue(categyId);
        String txCommand = category.getTxCommand();
        Map commandMap = objectMapper.readValue(txCommand, Map.class);

        //根据命令作为key来获取命令
        Map targetCommand = (Map) commandMap.get("command");
        Object finalCommand = targetCommand.get("command");

        //通过事件发送命令
        MyCommandHandler.sendControl(new CommandEvent(id, finalCommand));
    }

    @Override
    public void updateDeviceOnlineStatus(SysDevice device) {
        if (device.getIsOnline()==1){
            sysSceneMapper.updateOnline(device);
        }else {
            sysSceneMapper.updateOffline(device);
        }
    }
}
